package com.china.school;

import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.*;

public class SpringElTest02 {
    public static void main(String[] args) {

        //SpEl的目的，希望极可能的通过字符串编码的方式实现java编码

    }


    /**
     直接量表单式 字符串 8个基本类型及其包装类型
     */
    @Test
    public void test01(){
        SpelExpressionParser parser = new SpelExpressionParser();
        System.out.println(parser.parseExpression("'Hello world!'").getValue());
        System.out.println(parser.parseExpression("123").getValue()); //整形
        System.out.println(parser.parseExpression("123L").getValue());//长整型
        System.out.println(parser.parseExpression("123D").getValue()); //double双浮点型
        System.out.println(parser.parseExpression("123.0").getValue());//float单精度
        System.out.println(parser.parseExpression("'a'").getValue(char.class)); //字符型
        System.out.println(parser.parseExpression("600").getValue(Short.class)); //short型
        System.out.println(parser.parseExpression("127").getValue(byte.class)); //byte
        System.out.println(parser.parseExpression("true").getValue(boolean.class)); //boolean型
        System.out.println(parser.parseExpression("127").getValue(Byte.class)); //short型

    }

    /**
     数组类型
     */
    @Test
    public void test02(){
        SpelExpressionParser parser= new SpelExpressionParser();
        String[] arr1 = parser.parseExpression("new String[]{'小明','吃饭了'}").getValue(String[].class);
        int[] arr2 = parser.parseExpression("new int[]{1,2}").getValue(int[].class);


        System.out.println(Arrays.toString(arr1));
        System.out.println(Arrays.toString(arr2));

    }

    /**
     集合类型
     */
    @Test
    public void test03(){
            SpelExpressionParser parser= new SpelExpressionParser();
            List list1 = parser.parseExpression("{'小明','吃饭了'}").getValue(List.class);
            List<Integer> list2 = parser.parseExpression("{1,2,3,3,1,2,3}").getValue(List.class );
            Set<Integer> set3 = parser.parseExpression("{1,2,3,3,1,2,3}").getValue(Set.class );


        System.out.println(list1);
        System.out.println(list2);
        System.out.println(set3);
        System.out.println(parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:'1856'}}").getValue( ));

    }


    /**
     映射map集合
     */
    @Test
    public void test04(){
        // 创建一个 Map 对象
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 10);
        map.put("banana", 5);
        map.put("orange", 8);

        // 创建 SpelExpressionParser 对象
        SpelExpressionParser parser = new SpelExpressionParser();

        // 创建 EvaluationContext 对象，并将 Map 对象设置为根对象
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setRootObject(map);
        context.setVariable("map1",map);

        System.out.println("从参数容器中计算值" + parser.parseExpression("#map1[apple] + #map1[banana]").getValue(context, Integer.class));
        System.out.println("从参数对象中计算值" + parser.parseExpression("[apple] + [banana]").getValue(context, Integer.class));
        System.out.println("从参数对象中计算值" + parser.parseExpression("[apple] + [banana]").getValue(map, Integer.class));
        System.out.println("从参数对象中计算值" + parser.parseExpression("[apple] + [banana]").getValue(map ));


    }

    /**
     方法的调用 ，调用参数对象或者参数容器中的对象必须通过#的方式去调用
     */

    @Test
    public void test05(){
        List<String> list = new ArrayList<>();
        list.add("小明");
        list.add("过来");
        list.add("吃饭了");

        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 10);
        map.put("banana", 5);

        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("map2",map);
        context.setVariable("list2",list);

        SpelExpressionParser parser = new SpelExpressionParser();
        System.out.println(parser.parseExpression("'Hello World'.substring(0,5)").getValue());
        //如果没有传递参数容器,传递的是参数对象，那么默认就可以通过root对象去调用
        System.out.println(parser.parseExpression("#root.put('orange', 8)").getValue(map));
        System.out.println(parser.parseExpression("#map2['orange']").getValue(context));
        System.out.println(parser.parseExpression("#root.get(0)").getValue(list));
        System.out.println(parser.parseExpression("#list2.get(0)").getValue(context));



    }


    /**
     算术运算符，比较运算符 ，逻辑运算符，赋值运算符，三目运算符
     */
    @Test
    public void test06(){
        List<String> list = new ArrayList<>();
        list.add("小明");
        list.add("过来");
        list.add("吃饭了");

        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 10);
        map.put("banana", 5);

        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("list",list);
        context.setVariable("map",map);

        SpelExpressionParser parser = new SpelExpressionParser();

        //三目运算符
        System.out.println(parser.parseExpression("#list.size()>3? '长度大于3':'长度小于或者等于3'").getValue(context));

        //赋值运算符
        System.out.println(parser.parseExpression("#list.set(0,'小李')").getValue(context));
        System.out.println(parser.parseExpression("#list.get(0)").getValue(context));

        //算数运算符
        System.out.println(parser.parseExpression("#map[apple] + #map[banana]").getValue(context));

        //逻辑运算符
        System.out.println(parser.parseExpression("((#map[apple] + #map[banana]) == 15) && true").getValue(context));

        //比较运算符
        System.out.println(parser.parseExpression("'apple是否大于2: ' + (#map[apple] > 2)").getValue(context));


    }
    /**
     类型运算符，就是类名调用方法
     */

    static private  SpelExpressionParser parser = new SpelExpressionParser();
    static private StandardEvaluationContext context = new StandardEvaluationContext();
    @Test
    public void test07(){

        //如果不是基础包的话需要引入完全的包名
        System.out.println("随机数" + parser.parseExpression("T(java.lang.Math).random()").getValue());

        //java.lang的基础包不需要引入完全的包名
        System.out.println("获取系统参数 " +parser.parseExpression("T(System).getProperty('os.name')").getValue());

    }

    /**
    调用构造器，直接通过java编码的方式即可，如果不是基础包的话需要填写完整的类名
     */

     @Test
    public void test08(){
         List<String> list = new ArrayList<>();
         list.add("小明");
         list.add("过来");
         list.add("吃饭了");
         context.setVariable("list",list);
         System.out.println(parser.parseExpression("new String('吃饭了').substring(0)").getValue());
         //调用构造器，传入参数
         System.out.println("list的长度" + parser.parseExpression("new java.util.ArrayList(#root).size()").getValue(list));
         System.out.println("list的长度" + parser.parseExpression("new java.util.ArrayList(#list).size()").getValue(context));

     }


    /**
     变量
     */
    @Test
    public void test09(){


        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("apple", 10);
        map.put("西瓜", 6);
        map.put("banana", 5);
        //对于8个基本类型的值是通过value来代替的
        System.out.println("收集V的值的集合" + parser.parseExpression("#root.![value]").getValue(map));
        System.out.println("收集V的值的集合" + parser.parseExpression("#root.![#this]").getValue(map));



    }
    /**
     自定义函数，为方法重新起个名字

     public static abstract class StringUtils {

     public static String reverseString(String input) {
     StringBuilder backwards = new StringBuilder(input.length());
     for (int i = 0; i < input.length(); i++) {
     backwards.append(input.charAt(input.length() - 1 - i));
     }
     return backwards.toString();
     }
     }

//    @Test
//    public void test10() throws NoSuchMethodException {
//        ExpressionParser parser = new SpelExpressionParser();
//
//        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
//        context.setVariable("reverseString",
//                StringUtils.class.getDeclaredMethod("reverseString", String.class));
//
//        String helloWorldReversed = parser.parseExpression(
//                "#reverseString('hello')").getValue(context, String.class);
//        System.out.println(helloWorldReversed);
//    }

     //似乎只能是静态方法
     */
    @Test
    public void test10() throws NoSuchMethodException {
        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
        Method method = String.class.getDeclaredMethod("valueOf",char[].class);
        context.setVariable("valueOf",method);
          System.out.println(parser.parseExpression("#valueOf(new char[]{'a','b'})").getValue(context));

    }
    /**
    安全导航操作
     */
    @Test
    public void test11(){

        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 10);
        map.put("banana", 5);
         context.setVariable("map",map);
        System.out.println("打印第四个字符串的长度" + parser.parseExpression("#map.get('西瓜')?.length").getValue(context));

    }


    /**
     集合选择
     */
    @Test
    public void test12(){

        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 10);
        map.put("西瓜", 6);
        map.put("banana", 5);
        //对于8个基本类型的值是通过value来代替的
         System.out.println("选择值大于5的元素" + parser.parseExpression("#root.?[value>5]").getValue(map));
    }




    /**
     集合投影运算法： 就是相当于for循环遍历集合中的元素
     */
    @Test
    public void test13(){

        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("apple", 10);
        map.put("西瓜", 6);
        map.put("banana", 5);
        //对于8个基本类型的值是通过value来代替的
        System.out.println("收集V的值的集合" + parser.parseExpression("#root.![value]").getValue(map));
        System.out.println("收集V的值的集合" + parser.parseExpression("#root.![#this]").getValue(map));
        System.out.println("V的平方的集合"+ parser.parseExpression("#root.![value * value]").getValue(map));
    }
    /**
     表达式模板: 本质是二次 SpEl表达式的解析
     */
    @Test
    public void test14(){

        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("apple", 10);
        map.put("西瓜", 6);
        map.put("banana", 5);

        User user = new User("小明",22);
        context.setRootObject(map);

           System.out.println("V的平方的集合"+ parser.parseExpression("香蕉价格:#{['banana']},西瓜价格:#{['西瓜']}",new TemplateParserContext()).getValue(context));
           //注意只有root的属性不用加#访问，其他的都需要加上#去访问,getValue的第二个参数代表root对象
           System.out.println("V的平方的集合"+ parser.parseExpression("小明的姓名:#{#root.name},年龄:#{#root.age}",new TemplateParserContext()).getValue(context,user,String.class));
           System.out.println("V的平方的集合"+ parser.parseExpression("小明的姓名:#{name},年龄:#{age}",new TemplateParserContext()).getValue(user));

    }
//要访问 factory Bean 本身，你应该在Bean的名字前加上一个 & 符号。下面的例子展示了如何做到这一点。

//如 果evaluation context 已经被配置了Bean解析器，你可以通过使用 @ 符号从表达式中查找Bean。下面的例子展示了如何做到这一点。

    }
